package com.daji.concurrency.multithread_future_callback;


/*
    知识点：使用Thread.currentThread()获取当前线程，如果进一步.getName()就可以获取当前线程名
    new Thread(() -> {
            System.out.println(Thread.currentThread().getName());
        }).start();
*/

//https://baijiahao.baidu.com/s?id=1653790035315010634&wfr=spider&for=pc
public class E05_ThreadLocal {

    //使用ThreadLocal 来声明一个线程局部变量
    static ThreadLocal<Integer> local = new ThreadLocal<>();


    public static void main(String[] args) throws Exception {
        //不使用Threadlocal：
        new Thread(() -> {
            System.out.println(Thread.currentThread().getName()+"不使用ThreadLocal");
            Integer n = 1;
            step1(n);
            step2(n);
            step3(n);
        }).start();

        //使用ThreadLocal，可以让一个局部变量在一个线程中传递。使用起来很简单
        new Thread(() -> {
            System.out.println(Thread.currentThread().getName()+"使用ThreadLocal");
            Integer n = 1;
            local.set(n);
            step1();
            step2();
            step3();
            System.out.println("使用ThreadLocal处理完成的结果："+local.get());  //5
        }).start();

        //ThreadLocal 是线程间隔离的 （Fixme 线程池可能出现问题，看下面的TODO）
        new Thread(() -> {
            System.out.println(Thread.currentThread().getName()+"新线程测试ThreadLocal的留存情况");
            System.out.println(Thread.currentThread().getName()+"使用ThreadLocal");
            Integer n = 100;
            local.set(n);
            step1();
            step2();
            step3();
            System.out.println("使用ThreadLocal处理完成的结果："+local.get());  //5
        }).start();

        //TODO 特别注意线程池的情况。上面ThreadLocal隔离的原因，是因为一个是Thread-2，一个是Thread-3
        //如果是线程池中应用这个ThreadLocal，Thread-2执行完了，还有可能再次被唤醒。在这种条件下一定要用finally语句清除掉这个ThreadLocal：
        /*
            最后，特别注意ThreadLocal一定要在finally中清除：
            try {
                threadLocalUser.set(user);
                ...
            } finally {
                threadLocalUser.remove();
            }
            这是因为当前线程执行完相关代码后，很可能会被重新放入线程池中，如果ThreadLocal没有被清除，该线程执行其他代码时，会把上一次的状态带进去。
        */

    }

    static void step1(Integer n) {
        n+=1;
        System.out.println("不使用ThreadLocal，步骤1过后n的值为："+n);
    }

    static void step2(Integer n) {
        n*=2;
        System.out.println("不使用ThreadLocal，步骤2过后n的值为："+n);
    }

    static void step3(Integer n) {
        n+=1;
        System.out.println("不使用ThreadLocal，步骤3过后n的值为："+n);
    }



    static void step1() {
        Integer n = local.get();
        n+=1;
        System.out.println("使用ThreadLocal，步骤1过后n的值为："+n);
        local.set(n);   //2
    }

    static void step2() {
        Integer n = local.get();
        n*=2;
        System.out.println("使用ThreadLocal，步骤2过后n的值为："+n);
        local.set(n);   //4
    }

    static void step3() {
        Integer n = local.get();
        n+=1;
        System.out.println("使用ThreadLocal，步骤3过后n的值为："+n);
        local.set(n);   //5
    }

}
